源代码
const readline = require('readline'); // 引入Node.js的readline模块,用于读取用户输入
// 创建一个readline接口实例,用于从标准输入(stdin)读取数据,并将结果输出到标准输出(stdout)
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
// 定义运算符的优先级,数字越大优先级越高
const precedence = {
'+': 1, // 加法优先级为1
'-': 1, // 减法优先级为1
'*': 2, // 乘法优先级为2
'/': 2 // 除法优先级为2
};
// 定义一个函数,用于根据运算符计算两个数的结果
function applyOperator(a, b, operator) {
// 根据运算符执行相应的运算
switch (operator) {
case '+': // 加法
return a + b;
case '-': // 减法
return a - b;
case '*': // 乘法
return a * b;
case '/': // 除法
// 检查除数是否为0,避免除以0的错误
if (b === 0) throw new Error("除数不能为零");
return a / b;
default: // 如果运算符不合法,抛出错误
throw new Error(`未知运算符: ${operator}`);
}
}
// 定义一个函数,用于计算数学表达式的值
function evaluateExpression(expr) {
// 移除表达式中的所有空格,避免空格干扰解析
expr = expr.replace(/\s+/g, '');
// 初始化两个栈:一个用于存储数字,另一个用于存储运算符
const numbers = []; // 数字栈
const operators = []; // 运算符栈
// 从左到右遍历表达式
let i = 0;
while (i < expr.length) {
// 如果当前字符是数字
if (/\d/.test(expr[i])) {
let numStr = ''; // 用于存储当前数字的字符串
// 继续读取数字,直到遇到非数字字符
while (i < expr.length && (/\d/.test(expr[i]) || expr[i] === '.')) {
numStr += expr[i]; // 将当前字符添加到数字字符串中
i++;
}
numbers.push(parseFloat(numStr)); // 将解析出的数字转换为浮点数并压入数字栈
}
// 如果当前字符是运算符
else if (expr[i] in precedence) {
// 如果运算符栈不为空,并且栈顶运算符的优先级大于或等于当前运算符的优先级
while (operators.length > 0 &&
precedence[operators[operators.length - 1]] >= precedence[expr[i]]) {
// 从数字栈中弹出两个数字
const b = numbers.pop();
const a = numbers.pop();
// 从运算符栈中弹出一个运算符
const op = operators.pop();
// 计算结果并压入数字栈
numbers.push(applyOperator(a, b, op));
}
// 将当前运算符压入运算符栈
operators.push(expr[i]);
i++;
} else {
// 如果遇到非法字符,抛出错误
throw new Error(`非法字符: ${expr[i]}`);
}
}
// 处理剩余的运算符
while (operators.length > 0) {
// 从数字栈中弹出两个数字
const b = numbers.pop();
const a = numbers.pop();
// 从运算符栈中弹出一个运算符
const op = operators.pop();
// 计算结果并压入数字栈
numbers.push(applyOperator(a, b, op));
}
// 如果数字栈中只有一个数字,说明表达式计算完成
if (numbers.length !== 1) {
throw new Error("表达式不完整");
}
// 返回最终结果
return numbers[0];
}
// 定义主交互函数,用于启动计算器
function startCalculator() {
// 打印欢迎信息和使用说明
console.log('=== 简单计算器 ===');
console.log('支持运算符: +, -, *, /');
console.log('示例输入: 3 + 5 * 2 / 4');
// 监听用户输入
rl.on('line', (input) => {
// 如果用户输入"exit",退出程序
if (input.toLowerCase() === 'exit') {
console.log('感谢使用计算器!');
rl.close(); // 关闭readline接口
return;
}
try {
// 尝试计算用户输入的表达式
const result = evaluateExpression(input);
// 输出计算结果,保留两位小数
console.log(`结果: ${result.toFixed(2)}`);
} catch (error) {
// 如果计算过程中发生错误,输出错误信息
console.log(`错误: ${error.message}`);
}
});
}
// 启动计算器
startCalculator();
运行结果
> 等待执行...
计算:
代码解释
引入模块和创建接口
通过`require('readline')`引入Node.js的`readline`模块,用于读取用户输入。然后创建`rl`实例,设置输入为标准输入`process.stdin`,输出为标准输出`process.stdout`,实现与用户的交互。
定义运算符优先级
使用对象`precedence`定义了四则运算符`+`、`-`、`*`、`/`的优先级,乘法和除法的优先级为2,加法和减法的优先级为1,数字越大优先级越高。
计算函数`applyOperator`
`applyOperator`函数根据传入的运算符,对两个数`a`和`b`执行相应的运算。在除法运算中,检查除数是否为0,如果为0则抛出错误,其他不合法的运算符也会抛出错误。
表达式求值函数`evaluateExpression`
该函数先移除表达式中的空格,然后初始化数字栈`numbers`和运算符栈`operators`。通过遍历表达式,将数字压入数字栈,根据运算符优先级处理运算符,最后处理剩余运算符,确保表达式按正确顺序计算,计算完成后返回结果。如果数字栈中最终不是只有一个数字,说明表达式不完整,会抛出错误。
主交互函数`startCalculator`
此函数打印欢迎信息和使用说明,然后监听用户输入。如果用户输入`exit`,关闭`readline`接口退出程序;否则尝试计算用户输入的表达式,输出计算结果或错误信息。